Fix #10944: unused EMS actuator warning never fires#11525
Fix #10944: unused EMS actuator warning never fires#11525brianlball wants to merge 5 commits intodevelopfrom
Conversation
IDF with actuator A1 + program `Set Al = 2` (typo). Expect err stream contains "Unused EMS Actuator detected A1" after checkForUnusedActuatorsAtEnd; stream is empty on develop. Fails on current source - verifies the gap.
1179f5f to
2469735
Compare
Prior attempt flipped Null sentinel initialized=false, which broke right-hand-side reads of actuators that hadn't been SET yet but had subsystem-provided default values (regressed EMSUserDefined5ZoneAirCooled, PythonPluginUserDefined5ZoneAirCooled). Value.initialized has dual meaning - both "safe to read as right-hand-side operand" and "was SET by Erl" - so co-opting it for the warning check was wrong. Per Myoldmopar's suggestion in the issue, add a dedicated `wasActuated` bool on ActuatorUsedType. Set it in the EMSManager.cc post-ManageEMS actuator-update loop (else branch where Type != Null, i.e. user SET a concrete value). Check it in checkForUnusedActuatorsAtEnd instead of Value.initialized. Leaves Null sentinel and Value.initialized semantics untouched.
2469735 to
e91fc19
Compare
|
Regression diffs — all expected, warning working as intendedThe regression tool flagged 13 files with diffs. All 13 are Pattern breakdown
Sample hit (EMSDemandManager_LargeOffice)ConclusionKeeping the warnings as-is. Each flagged actuator is a genuine declared-but-unused case. If the corpus authors meant these as placeholders, the warning now documents that; if they're dead, it flags them for cleanup. Either way, this is the fix working on real-world data. |
|
Myoldmopar
left a comment
There was a problem hiding this comment.
This seems like a reasonable change to get a nice warning if an ERL actuator is not used. My only additional comment would be that it would be nice to clean out the warnings that are now added from unused actuators in the test files. Even when there is good intention to clean out warnings later, it's very easy to not do them. Otherwise this is good.
| bool CheckedOkay; // set to true once matched to available actuator | ||
| int ErlVariableNum; // points to global Erl variable, matches Name | ||
| int ActuatorVariableNum; // points to index match in EMSActuatorAvailable structure | ||
| bool wasActuated = false; // issue #10944: true once any Erl program has set this actuator |
There was a problem hiding this comment.
Adding a flag here seems quite reasonable.
| EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); | ||
| EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()); | ||
|
|
||
| compare_err_stream(""); // drop any setup chatter |
There was a problem hiding this comment.
Good unit test. I'm not sure this call to compare_err_stream is needed since you are properly using the compare_err_stream_substring function below. The err stream does not need to be cleared of any chatter. It's not harming anything, but not necessary in the future.
Runtime wasActuated flip false-positived on idiomatic IF cond SET=v ELSE SET=NULL pattern when design-day runs never hit non-null branch. Move check to parse-time: flip on Erl SET target match. Python path flips on getActuatorHandle match. External/FMU already outside warning loop range.
BypassHXStatus + Chiller1PumpFlow from Hospital; Chiller1PumpFlow from OfficeLarge + 3 Chiller variants; HeatSys1_Boiler_Setpoint from two EMS demo LargeOffice IDFs. All declared, none ever SET in any Erl program.
…ears
Python-API test in EMSManager.unit.cc violated testing pattern and failed
Linux CI (missing include + state.get() on raw pointer). Keep single
Python test in datatransfer.unit.cc where fixture belongs. Also drop
compare_err_stream("") pre-clears per review - substring search is
targeted, collision with setup chatter impossible.
|
|
|
Trying to clean up the 13 flagged IDFs surfaced a problem with the runtime Of the 13, only 2 actuator declarations were truly dead:
The other 11 hits are the idiomatic EMS override pattern:
Re-reading #10944 — the goal is typo detection: Changes:
No `Unused EMS Actuator` warnings anywhere in the integration corpus. Regression tool on this branch: previous ERR: 13 → now Audit: 7 (actuator-count bookkeeping only, no simulation-output diffs). Pattern for parse-time flag flips mirrors #11409 (`SetByGlobalVariable` / `SetByInternalVariable`) — same style, reviewer-blessed precedent. |

Summary
checkForUnusedActuatorsAtEndcheckedErlVariable.Value.initialized, but that flag has dual meaning: "safe to read as right-hand-side operand" AND "was SET by Erl program". Actuators getinitialized=trueearly (inherited from the Null sentinel at registration) so the first meaning applies cleanly - but the guard read it as the second meaning and never tripped.wasActuatedbool onActuatorUsedType. Set it only when the user's Erl program assigns a concrete value to the actuator (Type != Null in the post-ManageEMS actuator-update loop atEMSManager.cc:345). Check that flag in the end-of-sim guard. LeavesValue.initializedand the Null sentinel alone.Why this approach (history)
First attempt flipped the Null sentinel's
initializedflag tofalse. That seemed surgical but broke right-hand-side reads of actuators that hadn't been SET yet but had subsystem-provided defaults - the expression evaluator atRuntimeLanguageProcessor.cc:1800reads the same flag to gate "is this variable safe to use in an expression." CI caught it via regressions inintegration.EMSUserDefined5ZoneAirCooledandintegration.PythonPluginUserDefined5ZoneAirCooled. The current fix matches Myoldmopar's original suggestion in the issue ("a simple flag on each actuator").Call graph - issue & fix
Files changed
src/EnergyPlus/DataRuntimeLanguage.hh- addwasActuatedfield onActuatorUsedTypesrc/EnergyPlus/EMSManager.cc- set the flag in the actuator-update else branch; check it in the end-of-sim guardtst/EnergyPlus/unit/EMSManager.unit.cc- newUnusedActuatorWarningtestTest plan
EnergyPlusFixture.UnusedActuatorWarningasserts warning fires for unused actuatorintegration.EMSUserDefined5ZoneAirCooled: passes locally (was the CI regression in the prior attempt)integration.EMS*tests: passscripts/check_gcc_warnings.py src/EnergyPlus/EMSManager.cc: clean